﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Storage;
using CC98.Network;
using CC98.Network.Primitives;

namespace CC98.Metro.Data
{
    /// <summary>
    /// Manage all user sessions and handle network session save & restore
    /// </summary>
    public class UserSessionManager
    {
        private static readonly object _syncRoot = new object();

        private static volatile UserSessionManager _instance;

        public static UserSessionManager Instance
        {
            get
            {
                if (_instance == null)
                    lock (_syncRoot)
                        if (_instance == null)
                            _instance = new UserSessionManager();
                return _instance;
            }
        }

        private UserSessionManager()
        {
            this.LoadSessions();
        }

        public UserSession Current
        {
            get
            {
                return null;
            }
            set
            {
                
            }
        }

        /// <summary>
        /// Thread safe method
        /// </summary>
        /// <param name="username"></param>
        /// <returns></returns>
        public UserSession GetSession(string username)
        {
            if (string.IsNullOrWhiteSpace(username))
                throw new ArgumentException("Invalid username");
            lock (this)
            {
                UserSession session = null;
                if (!this._sessionDict.TryGetValue(username, out session))
                {
                    session = new UserSession(new CC98Client(new CC98HttpClient(new CC98HttpClientHandler(username))));
                    session.AuthenticationStateChanged += Session_AuthenticationStateChanged;
                }
                return session;
            }
        }

        /// <summary>
        /// Get all sessions
        /// </summary>
        /// <returns></returns>
        public IEnumerable<UserSession> GetSessions()
        {
            return this._sessionDict.Values;
        }

        /// <summary>
        /// Save sessions to setting
        /// </summary>
        public void SaveSessions()
        {
            ApplicationDataContainer container = null;
            if (ApplicationData.Current.RoamingSettings.Containers.TryGetValue("session", out container))
            {
                container = ApplicationData.Current.RoamingSettings.CreateContainer("session", ApplicationDataCreateDisposition.Always);
            }

            foreach (var userSession in this._sessionDict.Values)
            {
                // Skip anonymous user
                if(userSession.User.IsAnonymouse)
                    continue;
                ApplicationDataContainer sessionContainer = null;
                if(!container.Containers.TryGetValue(userSession.User.Name, out sessionContainer))
                    sessionContainer = container.CreateContainer(userSession.User.Name, ApplicationDataCreateDisposition.Always);
                userSession.Client.GetSession().Write(sessionContainer);
            }
        }

        protected void OnSessionCollectionChanged()
        {
            if (this.SessionCollectionChanged != null)
                this.SessionCollectionChanged(this, new EventArgs());
        }

        protected void OnSessionAuthenticationChanged(UserSession session)
        {
            if (this.SessionAuthenticationStateChanged != null)
                this.SessionAuthenticationStateChanged(this, new SessionAuthenticationStateChangedEventArgs(session));
        }

        private void Session_AuthenticationStateChanged(object sender, EventArgs e)
        {
            this.OnSessionAuthenticationChanged((UserSession)sender);
        }

        public event EventHandler SessionCollectionChanged;

        public event EventHandler<SessionAuthenticationStateChangedEventArgs> SessionAuthenticationStateChanged;

        public event EventHandler CurrentChanged;

        protected void LoadSessions()
        {
            // Load network session
            List<Session> sessions = new List<Session>();

            ApplicationDataContainer container = null;
            if (ApplicationData.Current.RoamingSettings.Containers.TryGetValue("session", out container))
            {
                foreach (var sessionContainer in container.Containers)
                {
                    var session = new Session(sessionContainer.Value);
                    sessions.Add(session);
                }
            }
            // Create user sessions
            foreach (var session in sessions)
            {
                if (!this._sessionDict.ContainsKey(session.Username))
                {
                    var userSession = new UserSession(new CC98Client(new CC98HttpClient(new CC98HttpClientHandler(session))));
                    userSession.AuthenticationStateChanged += Session_AuthenticationStateChanged;
                    this._sessionDict[session.Username] = userSession;
                }
            }
        }

        private readonly Dictionary<string, UserSession> _sessionDict = new Dictionary<string, UserSession>();
    }
}
